﻿@page "/external-services"
@using System.Text.Json
@using System.Text.Json.Nodes
@attribute [StreamRendering]
@inject IHttpClientFactory HttpClientFactory

<PageTitle>External Services</PageTitle>

<h1>External Services</h1>

<p>This component demonstrates communicating with external services.</p>

<h2>Direct to External Services</h2>
<p>
    <strong>NuGet API version: </strong>
    @if (nugetApiVersion == null)
    {
        <em>loading...</em>
    }
    else
    {
         @nugetApiVersion
    }
</p>

<p><strong>Response from @externalServiceUrl: </strong> 
@if (externalServiceStatus == null)
{
    <em>loading...</em>
}
else
{
    @externalServiceStatus
}
</p>

<h2>Via YARP gateway</h2>
<p>
    <strong>NuGet API version: </strong>
    @if (gatewayNugetApiVersion == null)
    {
        <em>loading...</em>
    }
    else
    {
        @gatewayNugetApiVersion
    }
</p>

<p>
    <strong>Response from @gatewayExternalServiceUrl: </strong>
    @if (gatewayExternalServiceStatus == null)
    {
        <em>loading...</em>
    }
    else
    {
        @gatewayExternalServiceStatus
    }
</p>

@code {
    private string? externalServiceUrl;
    private string? nugetApiVersion;
    private string? externalServiceStatus;
    private string? gatewayExternalServiceUrl;
    private string? gatewayNugetApiVersion;
    private string? gatewayExternalServiceStatus;

    protected override async Task OnInitializedAsync()
    {
        var externalServiceClient = HttpClientFactory.CreateClient("external-service");
        externalServiceUrl = externalServiceClient.BaseAddress?.ToString();
        var externalServiceTask = GetExternalServiceStatus(externalServiceClient);

        var nugetClient = HttpClientFactory.CreateClient("nuget");
        var nugetTask = GetNuGetVersion(nugetClient);

        var gatewayClient = HttpClientFactory.CreateClient("gateway");
        gatewayExternalServiceUrl = new Uri(gatewayClient.BaseAddress!, "/external-service").ToString();
        var gatewayExternalServiceTask = GetExternalServiceStatus(gatewayClient, "external-service");
        var gatewayNugetTask = GetNuGetVersion(gatewayClient, "nuget");

        externalServiceStatus = await externalServiceTask;
        nugetApiVersion = await nugetTask;
        gatewayExternalServiceStatus = await gatewayExternalServiceTask;
        gatewayNugetApiVersion = await gatewayNugetTask;
    }

    private async Task<string> GetExternalServiceStatus(HttpClient client, string? pathPrefix = null)
    {
        try
        {
            var path = $"{pathPrefix}";
            var response = await client.GetAsync(path);
            return response.StatusCode.ToString();
        }
        catch (Exception ex)
        {
            return $"Error: {ex.Message}";
        }
    }

    private async Task<string?> GetNuGetVersion(HttpClient client, string? pathPrefix = null)
    {
        try
        {
            var path = $"{pathPrefix}/v3/index.json";
            var response = await client.GetAsync(path);
            response.EnsureSuccessStatusCode();

            using var contentStream = await response.Content.ReadAsStreamAsync();

            return await GetPropertyValueAsync(contentStream, "version");
        }
        catch (Exception ex)
        {
            return $"Error: {ex.Message}";
        }
    }

    public static async Task<string?> GetPropertyValueAsync(Stream jsonStream, string propertyName)
    {
        // Parse the JSON asynchronously until we get the version property
        var buffer = new byte[256];
        int bytesRead;
        var jsonReaderState = new JsonReaderState();

        while ((bytesRead = await jsonStream.ReadAsync(buffer)) > 0)
        {
            var span = new ReadOnlySpan<byte>(buffer, 0, bytesRead);
            var reader = new Utf8JsonReader(span, isFinalBlock: false, state: jsonReaderState);

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.PropertyName && reader.ValueTextEquals(propertyName))
                {
                    // Read the next token to get the value
                    if (!reader.Read())
                    {
                        throw new JsonException("Unexpected end after 'version' property.");
                    }

                    if (reader.TokenType != JsonTokenType.String && reader.TokenType != JsonTokenType.Number)
                    {
                        throw new JsonException($"Unexpected token type for 'version': {reader.TokenType}");
                    }

                    return reader.GetString();
                }
            }

            jsonReaderState = reader.CurrentState;
        }

        return null; // "version" not found
    }
}
